1# -*- coding: utf-8 -*-
2
3#-------------------------------------------------------------------------------
4
5# This file is part of Code_Saturne, a general-purpose CFD tool.
6#
7# Copyright (C) 1998-2021 EDF S.A.
8#
9# This program is free software; you can redistribute it and/or modify it under
10# the terms of the GNU General Public License as published by the Free Software
11# Foundation; either version 2 of the License, or (at your option) any later
12# version.
13#
14# This program is distributed in the hope that it will be useful, but WITHOUT
15# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17# details.
18#
19# You should have received a copy of the GNU General Public License along with
20# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
21# Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23#-------------------------------------------------------------------------------
24
25"""
26This module defines the 'Start/Restart' page.
27
28This module defines the following classes:
29- StartRestartModel
30- StartRestartTestCase
31"""
32
33#-------------------------------------------------------------------------------
34# Library modules import
35#-------------------------------------------------------------------------------
36
37import os, sys, types
38import unittest
39
40#-------------------------------------------------------------------------------
41# Application modules import
42#-------------------------------------------------------------------------------
43
44from code_saturne.model.Common import *
45from code_saturne.model.XMLvariables import Model, Variables
46from code_saturne.model.XMLmodel import ModelTest
47
48#-------------------------------------------------------------------------------
49# Get info on a given restart path
50#-------------------------------------------------------------------------------
51
52def getRestartInfo(package, results_dir=None, restart_path='*'):
53    """
54    Return a tuple (path, number of time steps, time value) or None
55    describing the current restart selection.
56    """
57
58    restart_input = None
59
60    from code_saturne.cs_exec_environment import get_command_output, assemble_args
61
62    nt_names = ('nbre_pas_de_temps', 'ntcabs')
63    t_names = ('instant_precedent', 'ttcabs')
64
65    results = []
66
67    if results_dir and restart_path == '*':
68        results = os.listdir(results_dir)
69        results.sort(reverse=True)
70    elif restart_path:
71        results = [restart_path,]
72
73    io_dump = package.get_io_dump()
74
75    for r in results:
76        if restart_path == '*':
77            m = os.path.join(results_dir, r, 'checkpoint', 'main')
78        else:
79            m = os.path.join(r, 'main')
80        if not os.path.isfile(m):
81            m += '.csc'
82        if os.path.isfile(m):
83            if True: # try:
84                nt = -1
85                for name in nt_names:
86                    cmd = [io_dump, '-e', '--section']
87                    cmd.append(name)
88                    cmd.append(m)
89                    cmd_str = assemble_args(cmd)
90                    res = get_command_output(cmd_str)
91                    if res:
92                        nt = -1
93                        try:
94                            nt = int(res.strip())
95                            break
96                        except Exception:
97                            pass
98                t = -1
99                for name in t_names:
100                    cmd = [io_dump, '-e', '--section']
101                    cmd.append(name)
102                    cmd.append(m)
103                    cmd_str = assemble_args(cmd)
104                    res = get_command_output(cmd_str)
105                    if res:
106                        t = -1
107                        try:
108                            t = float(res.strip())
109                            break
110                        except Exception:
111                            pass
112
113                return (os.path.split(m)[0], nt, t)
114
115            elif False: # except Exception:
116                d = os.path.split(m)[0]
117                print('checkpoint: ' + d + ' does not seem usable')
118                continue
119            restart_input = os.path.join(results_dir, r, 'checkpoint')
120            break
121
122    return None
123
124
125#-------------------------------------------------------------------------------
126# Start-Restart model class
127#-------------------------------------------------------------------------------
128
129class StartRestartModel(Model):
130    """
131    Manage the input/output markups in the xml doc about Start and Restart
132    """
133    def __init__(self, case):
134        """
135        Constuctor.
136        """
137        self.case = case
138        node_magt = self.case.xmlInitNode('calculation_management')
139        self.node_start = node_magt.xmlInitNode('start_restart')
140
141
142    def _defaultStartRestartValues(self):
143        """
144        Return in a dictionnary which contains default values
145        """
146        default = {}
147        default['restart']                = "off"
148        default['frozen_field']           = "off"
149        default['restart_with_auxiliary'] = "on"
150        default['restart_rescue']         = 0
151        default['period_rescue']          = "4 output"
152        return default
153
154
155    @Variables.noUndo
156    def getRestartPath(self):
157        """
158        Return restart path if applicable; use '*' for automatic mode.
159        """
160        restart = None
161        node = self.node_start.xmlGetNode('restart', 'path')
162        if node:
163            restart = node['path']
164        return restart
165
166
167    @Variables.undoLocal
168    def setRestartPath(self, v):
169        """
170        Set restart path if applicable; use '*' for automatic mode.
171        """
172        node = self.node_start.xmlGetNode('restart')
173        if v:
174            if not node:
175                node = self.node_start.xmlInitNode('restart', 'path')
176            node['path'] = v
177        elif node:
178            node.xmlRemoveNode()
179            for n in self.case.xmlGetNodeList('time_average'):
180                n.xmlRemoveChild('restart_from_time_average')
181
182
183    @Variables.noUndo
184    def getRestartMeshPath(self):
185        """
186        Return restart mesh path if applicable
187        """
188        restart_mesh = None
189        node = self.node_start.xmlGetNode('restart_mesh', 'path')
190        if node:
191            restart_mesh = node['path']
192        return restart_mesh
193
194
195    @Variables.undoLocal
196    def setRestartMeshPath(self, v):
197        """
198        Set restart mesh path if applicable
199        """
200        node = self.node_start.xmlGetNode('restart_mesh')
201        if v:
202            if not node:
203                node = self.node_start.xmlInitNode('restart_mesh', 'path')
204            node['path'] = v
205        elif node:
206            node.xmlRemoveNode()
207
208
209    @Variables.noUndo
210    def getFrozenField(self):
211        """
212        Return if the velocity and the pressure are solved
213        """
214        node = self.node_start.xmlInitNode('frozen_field', 'status')
215        status = node['status']
216        if not status:
217            v = self._defaultStartRestartValues()['frozen_field']
218            self.setFrozenField(v)
219        return status
220
221
222    @Variables.undoLocal
223    def setFrozenField(self, v):
224        """
225        """
226        self.isOnOff(v)
227        node = self.node_start.xmlInitNode('frozen_field', 'status')
228        node['status'] = v
229
230
231    @Variables.noUndo
232    def getRestartWithAuxiliaryStatus(self):
233        """
234        Return status of reading auxiliary restart file for advanced options.
235        """
236        node = self.node_start.xmlInitNode('restart_with_auxiliary', 'status')
237        status = node['status']
238        if not status:
239            status = self._defaultStartRestartValues()['restart_with_auxiliary']
240            self.setRestartWithAuxiliaryStatus(status)
241        return status
242
243
244    @Variables.noUndo
245    def getRestartRescue(self):
246        """
247        Return frequency for restart checkpoints from advanced options.
248        """
249        val = self.node_start.xmlGetInt('restart_rescue')
250        if val == None or val == 0:
251            period = self._defaultStartRestartValues()['period_rescue']
252            val = self._defaultStartRestartValues()['restart_rescue']
253            self.setRestartRescue(val)
254        else:
255            if val == -2:
256                period = "Never"
257            elif val == -1:
258                period = "At the end"
259            else:
260                period = "Frequency"
261        return val, period
262
263
264    @Variables.undoLocal
265    def setRestartWithAuxiliaryStatus(self, status):
266        """
267        Input status of reading auxiliary restart file for advanced options.
268        """
269        self.isOnOff(status)
270        node = self.node_start.xmlInitNode('restart_with_auxiliary', 'status')
271        if status != self._defaultStartRestartValues()['restart_with_auxiliary']:
272            node['status'] = status
273        else:
274            node.xmlRemoveNode()
275
276
277    @Variables.undoLocal
278    def setRestartRescue(self, freq):
279        """
280        Inputfrequency for restart checkpoints from advanced options.
281        """
282        self.isInt(freq)
283        self.node_start.xmlSetData('restart_rescue', freq)
284
285
286#-------------------------------------------------------------------------------
287# StartRestartModel test case
288#-------------------------------------------------------------------------------
289
290
291class StartRestartTestCase(ModelTest):
292    """
293    """
294    def checkStartRestartInstantiation(self):
295        """
296        Check whether the StartRestartModel class could be instantiated
297        """
298        model = None
299        model = StartRestartModel(self.case)
300        assert model != None, 'Could not instantiate StartRestartModel'
301
302    def checkSetandGetRestart(self):
303        """
304        Check whether the restart method could be set and get
305        """
306        model = StartRestartModel(self.case)
307        model.setRestartPath("RESU/test/restart")
308        doc= '''<start_restart>
309                    <restart path="RESU/test/restart"/>
310                </start_restart>'''
311
312        assert model.node_start == self.xmlNodeFromString(doc),\
313                    'Could not set restart in StartRestart model'
314        assert model.getRestartPath() == 'RESU/test/restart',\
315                    'Could not get restart in StartRestart model'
316
317    def checkSetandGetFrozenStatus(self):
318        """
319        Check whether the Frozen status method could be set and get
320        """
321        model = StartRestartModel(self.case)
322        model.setRestart("on")
323        model.setFrozenField('on')
324        doc = '''<start_restart>
325                    <restart status="on"/>
326                    <frozen_field status="on"/>
327                 </start_restart>'''
328        assert model.node_start == self.xmlNodeFromString(doc),\
329                'Could not set frozen status in StartRestart model'
330        assert model.getFrozenField() == "on",\
331                'Could not get frozen status in StartRestart model'
332
333    def checkSetAuxiliaryRestartStatus(self):
334        """
335        Check whether the  Auxiliary Restart Status method
336        could be set and get
337        """
338        model = StartRestartModel(self.case)
339        model.setRestart("on")
340        model.setRestartWithAuxiliaryStatus('on')
341        doc= '''<start_restart>
342                    <restart status="on"/>
343                    <restart_with_auxiliary status="on"/>
344                </start_restart>'''
345        assert model.node_start == self.xmlNodeFromString(doc),\
346                'Could not set auxiliary restart status in StartRestart model'
347        assert model.getRestartWithAuxiliaryStatus() == "on",\
348                'Could not get auxiliary restart status in StartRestart model'
349
350    def checkSetandGetRestartRescue(self):
351        """
352        Check whether the  Restart rescue could be set and get
353        """
354        model = StartRestartModel(self.case)
355        model.setRestart("on")
356        model.setRestartRescue(15)
357        doc = '''<start_restart>
358                    <restart status="on"/>
359                    <restart_rescue>15</restart_rescue>
360                 </start_restart>'''
361        assert model.node_start == self.xmlNodeFromString(doc),\
362                'Could not set restart rescue value in StartRestart model'
363        freq, period = model.getRestartRescue()
364        assert freq == 15,\
365                'Could not get restart rescue value in StartRestart model'
366        assert period == "Frequency",\
367                'Could not get restart rescue period in StartRestart model'
368
369        model.setRestartRescue(-1)
370        freq, period = model.getRestartRescue()
371        assert freq == -1,\
372                'Could not get restart rescue value in StartRestart model'
373        assert period == "At the end",\
374                'Could not get restart rescue period in StartRestart model'
375
376
377def suite():
378    testSuite = unittest.makeSuite(StartRestartTestCase, "check")
379    return testSuite
380
381
382def runTest():
383    print("StartRestartTestCase")
384    runner = unittest.TextTestRunner()
385    runner.run(suite())
386
387
388#-------------------------------------------------------------------------------
389# End
390#-------------------------------------------------------------------------------
391