From 8e68b9916154f66de91e497e8e1b36ca2ac75b5c Mon Sep 17 00:00:00 2001 From: David Seus <david.seus@ians.uni-stuttgart.de> Date: Tue, 10 Sep 2019 13:31:35 +0200 Subject: [PATCH] clean up run(). fix write to disc --- LDDsimulation/domainPatch.py | 4 +- ...TP-TP-2-patch-pure-dd-convergence-study.py | 26 +- .../TP-TP-2-patch-alterantive.py | 303 ++++++++++-------- TP-TP-2-patch-test-case/TP-TP-2-patch-test.py | 171 ++++++---- 4 files changed, 286 insertions(+), 218 deletions(-) diff --git a/LDDsimulation/domainPatch.py b/LDDsimulation/domainPatch.py index 9b02d78..6e69ec9 100644 --- a/LDDsimulation/domainPatch.py +++ b/LDDsimulation/domainPatch.py @@ -904,7 +904,7 @@ class DomainPatch(df.SubDomain): self.ds = df.Measure('ds', domain = self.mesh, subdomain_data = self.interface_marker) - def _calc_interface_dof_indices_and_coordinates(self, debug: bool = True): + def _calc_interface_dof_indices_and_coordinates(self, debug: bool = False): """ calculate dictionaries containing for each local facet index of interfaces a dictionary containing {interface_dof_index: dof_coordinates} """ @@ -944,7 +944,7 @@ class DomainPatch(df.SubDomain): ) - def _calc_corresponding_dof_indices(self, debug=True): + def _calc_corresponding_dof_indices(self, debug=False): """ calculate dictionary which for each interface and each phase holds for each facet index, the dof indices of the pressures and flux components corresponding to a given dof index of the gli function. diff --git a/TP-TP-2-patch-pure-dd-avoid-interface-at-origin/mesh_study_convergence/TP-TP-2-patch-pure-dd-convergence-study.py b/TP-TP-2-patch-pure-dd-avoid-interface-at-origin/mesh_study_convergence/TP-TP-2-patch-pure-dd-convergence-study.py index 2336cf7..a9195f7 100755 --- a/TP-TP-2-patch-pure-dd-avoid-interface-at-origin/mesh_study_convergence/TP-TP-2-patch-pure-dd-convergence-study.py +++ b/TP-TP-2-patch-pure-dd-avoid-interface-at-origin/mesh_study_convergence/TP-TP-2-patch-pure-dd-convergence-study.py @@ -19,7 +19,7 @@ datestr = date.strftime("%Y-%m-%d") # init sympy session sym.init_printing() -use_case = "TP-TP-2-patch-pure-dd-mesh-study" +use_case = "TP-TP-2-patch-pure-dd" solver_tol = 6E-7 max_iter_num = 1000 FEM_Lagrange_degree = 1 @@ -51,6 +51,7 @@ output_string = "./output/{}-{}_timesteps{}_P{}-solver_tol{}".format(datestr, us # toggle what should be written to files if mesh_study: write_to_file = { + 'space_errornorms': True, 'meshes_and_markers': True, 'L_iterations_per_timestep': False, 'solutions': False, @@ -60,6 +61,7 @@ if mesh_study: } else: write_to_file = { + 'space_errornorms': True, 'meshes_and_markers': True, 'L_iterations_per_timestep': False, 'solutions': True, @@ -535,29 +537,7 @@ for subdomain in isRichards.keys(): # # sa -# toggle what should be written to files -if mesh_study: - write_to_file = { - 'meshes_and_markers': True, - 'L_iterations_per_timestep': False, - 'solutions': False, - 'absolute_differences': False, - 'condition_numbers': analyse_condition, - 'subsequent_errors': False - } -else: - write_to_file = { - 'meshes_and_markers': True, - 'L_iterations_per_timestep': False, - 'solutions': True, - 'absolute_differences': True, - 'condition_numbers': analyse_condition, - 'subsequent_errors': True - } - - for mesh_resolution in resolutions: - use_case = use_case + "-mesh-res_{}".format(mesh_resolution) # initialise LDD simulation class simulation = ldd.LDDsimulation( tol=1E-14, diff --git a/TP-TP-2-patch-test-case/TP-TP-2-patch-alterantive.py b/TP-TP-2-patch-test-case/TP-TP-2-patch-alterantive.py index 5d31e8e..1df40d9 100755 --- a/TP-TP-2-patch-test-case/TP-TP-2-patch-alterantive.py +++ b/TP-TP-2-patch-test-case/TP-TP-2-patch-alterantive.py @@ -7,11 +7,70 @@ import typing as tp import domainPatch as dp import LDDsimulation as ldd import functools as ft +import helpers as hlp +import datetime +import os +import pandas as pd + +date = datetime.datetime.now() +datestr = date.strftime("%Y-%m-%d") #import ufl as ufl # init sympy session sym.init_printing() +use_case = "TP-TP-2-patch-alternative" +solver_tol = 5E-7 +max_iter_num = 10 +FEM_Lagrange_degree = 1 +mesh_study = False +resolutions = [20] + +############ GRID ####################### +# mesh_resolution = 20 +timestep_size = 0.0001 +number_of_timesteps = 50 +# smallest possible number is 1 +plot_timestep_every = 5 +# decide how many timesteps you want analysed. Analysed means, that we write out +# subsequent errors of the L-iteration within the timestep. +number_of_timesteps_to_analyse = 0 +starttime = 0.0 + +Lw = 0.25 #/timestep_size +Lnw=Lw + +lambda_w = 40 +lambda_nw = 40 + +include_gravity = False +debugflag = False +analyse_condition = False + +output_string = "./output/{}-{}_timesteps{}_P{}_solver_tol{}_".format(datestr, use_case, number_of_timesteps, FEM_Lagrange_degree, solver_tol) + +# toggle what should be written to files +if mesh_study: + write_to_file = { + 'space_errornorms': True, + 'meshes_and_markers': True, + 'L_iterations_per_timestep': False, + 'solutions': False, + 'absolute_differences': False, + 'condition_numbers': analyse_condition, + 'subsequent_errors': False + } +else: + write_to_file = { + 'space_errornorms': True, + 'meshes_and_markers': True, + 'L_iterations_per_timestep': False, + 'solutions': True, + 'absolute_differences': True, + 'condition_numbers': analyse_condition, + 'subsequent_errors': True + } + ##### Domain and Interface #### # global simulation domain domain sub_domain0_vertices = [df.Point(-1.0,-1.0), # @@ -88,20 +147,6 @@ isRichards = { } -solver_tol = 1E-6 - -############ GRID #######################ü -mesh_resolution = 30 -timestep_size = 0.001 -number_of_timesteps = 1500 -# decide how many timesteps you want analysed. Analysed means, that we write out -# subsequent errors of the L-iteration within the timestep. -number_of_timesteps_to_analyse = 11 -starttime = 0 - -Lw = 100/timestep_size -Lnw=Lw - viscosity = {# # subdom_num : viscosity 1 : {'wetting' :1, @@ -134,14 +179,12 @@ L = {# 'nonwetting': Lnw} } -l_param_w = 25 -l_param_nw = 25 lambda_param = {# # subdom_num : lambda parameter for the L-scheme - 1 : {'wetting' :l_param_w, - 'nonwetting': l_param_nw},# - 2 : {'wetting' :l_param_w, - 'nonwetting': l_param_nw} + 1 : {'wetting' :lambda_w, + 'nonwetting': lambda_nw},# + 2 : {'wetting' :lambda_w, + 'nonwetting': lambda_nw} } ## relative permeabilty functions on subdomain 1 @@ -191,7 +234,7 @@ def rel_perm1w_prime(s): def rel_perm1nw_prime(s): # relative permeabilty on subdomain1 - return 2*(1-s) + return -2*(1-s) # # definition of the derivatives of the relative permeabilities # # relative permeabilty functions on subdomain 1 @@ -201,7 +244,7 @@ def rel_perm2w_prime(s): def rel_perm2nw_prime(s): # relative permeabilty on subdomain1 - return 3*(1-s)**2 + return -3*(1-s)**2 _rel_perm1w_prime = ft.partial(rel_perm1w_prime) _rel_perm1nw_prime = ft.partial(rel_perm1nw_prime) @@ -324,93 +367,44 @@ x, y = sym.symbols('x[0], x[1]') # needed by UFL t = sym.symbols('t', positive=True) p_e_sym = { - 1: {'wetting': -5 - (1+t*t)*(1 + x*x + y*y), - 'nonwetting': -2 -t*(1-y + x**2)**2}, - 2: {'wetting': -5.0 - (1.0 + t*t)*(1.0 + x*x), + 1: {'wetting': -7 - (1+t*t)*(1 + x*x + y*y), + 'nonwetting': -2 -t*(1 + y + x**2)}, + 2: {'wetting': -7.0 - (1.0 + t*t)*(1.0 + x*x), 'nonwetting': -2 -t*(1 + x**2)**2 - sym.sqrt(2+t**2)*(1+y)**2*x**2*y**2}, } -pc_e_sym = { - 1: p_e_sym[1]['nonwetting'] - p_e_sym[1]['wetting'], - 2: p_e_sym[2]['nonwetting'] - p_e_sym[2]['wetting'], -} - +pc_e_sym = dict() +for subdomain, isR in isRichards.items(): + if isR: + pc_e_sym.update({subdomain: -p_e_sym[subdomain]['wetting'].copy()}) + else: + pc_e_sym.update({subdomain: p_e_sym[subdomain]['nonwetting'].copy() + - p_e_sym[subdomain]['wetting'].copy()}) -# pc_e_sym = { -# 1: -1*p_e_sym[1]['wetting'], -# 2: -1*p_e_sym[2]['wetting'], -# } +symbols = {"x": x, + "y": y, + "t": t} # turn above symbolic code into exact solution for dolphin and # construct the rhs that matches the above exact solution. -dtS = dict() -div_flux = dict() -source_expression = dict() -exact_solution = dict() -initial_condition = dict() -for subdomain, isR in isRichards.items(): - dtS.update({subdomain: dict()}) - div_flux.update({subdomain: dict()}) - source_expression.update({subdomain: dict()}) - exact_solution.update({subdomain: dict()}) - initial_condition.update({subdomain: dict()}) - if isR: - subdomain_has_phases = ["wetting"] - else: - subdomain_has_phases = ["wetting", "nonwetting"] - - # conditional for S_pc_prime - pc = pc_e_sym[subdomain] - dtpc = sym.diff(pc, t, 1) - dxpc = sym.diff(pc, x, 1) - dypc = sym.diff(pc, y, 1) - S = sym.Piecewise((S_pc_sym[subdomain](pc), pc > 0), (1, True)) - dS = sym.Piecewise((S_pc_sym_prime[subdomain](pc), pc > 0), (0, True)) - for phase in subdomain_has_phases: - # Turn above symbolic expression for exact solution into c code - exact_solution[subdomain].update( - {phase: sym.printing.ccode(p_e_sym[subdomain][phase])} - ) - # save the c code for initial conditions - initial_condition[subdomain].update( - {phase: sym.printing.ccode(p_e_sym[subdomain][phase].subs(t, 0))} - ) - if phase == "nonwetting": - dtS[subdomain].update( - {phase: -porosity[subdomain]*dS*dtpc} - ) - else: - dtS[subdomain].update( - {phase: porosity[subdomain]*dS*dtpc} - ) - pa = p_e_sym[subdomain][phase] - dxpa = sym.diff(pa, x, 1) - dxdxpa = sym.diff(pa, x, 2) - dypa = sym.diff(pa, y, 1) - dydypa = sym.diff(pa, y, 2) - mu = viscosity[subdomain][phase] - ka = relative_permeability[subdomain][phase] - dka = ka_prime[subdomain][phase] - rho = densities[subdomain][phase] - g = gravity_acceleration - - if phase == "nonwetting": - # x part of div(flux) for nonwetting - dxdxflux = -1/mu*dka(1-S)*dS*dxpc*dxpa + 1/mu*dxdxpa*ka(1-S) - # y part of div(flux) for nonwetting - dydyflux = -1/mu*dka(1-S)*dS*dypc*(dypa - rho*g) \ - + 1/mu*dydypa*ka(1-S) - else: - # x part of div(flux) for wetting - dxdxflux = 1/mu*dka(S)*dS*dxpc*dxpa + 1/mu*dxdxpa*ka(S) - # y part of div(flux) for wetting - dydyflux = 1/mu*dka(S)*dS*dypc*(dypa - rho*g) + 1/mu*dydypa*ka(S) - div_flux[subdomain].update({phase: dxdxflux + dydyflux}) - contructed_rhs = dtS[subdomain][phase] - div_flux[subdomain][phase] - source_expression[subdomain].update( - {phase: sym.printing.ccode(contructed_rhs)} - ) - # print(f"source_expression[{subdomain}][{phase}] =", source_expression[subdomain][phase]) +exact_solution_example = hlp.generate_exact_solution_expressions( + symbols=symbols, + isRichards=isRichards, + symbolic_pressure=p_e_sym, + symbolic_capillary_pressure=pc_e_sym, + saturation_pressure_relationship=S_pc_sym, + saturation_pressure_relationship_prime=S_pc_sym_prime, + viscosity=viscosity, + porosity=porosity, + relative_permeability=relative_permeability, + relative_permeability_prime=ka_prime, + densities=densities, + gravity_acceleration=gravity_acceleration, + include_gravity=include_gravity, + ) +source_expression = exact_solution_example['source'] +exact_solution = exact_solution_example['exact_solution'] +initial_condition = exact_solution_example['initial_condition'] # Dictionary of dirichlet boundary conditions. dirichletBC = dict() @@ -447,40 +441,71 @@ for subdomain in isRichards.keys(): # # sa -write_to_file = { - 'meshes_and_markers': True, - 'L_iterations': True -} - - -# initialise LDD simulation class -simulation = ldd.LDDsimulation(tol = 1E-14, LDDsolver_tol = solver_tol, debug = True) -simulation.set_parameters(output_dir = "./output/alternative_example/",# - subdomain_def_points = subdomain_def_points,# - isRichards = isRichards,# - interface_def_points = interface_def_points,# - outer_boundary_def_points = outer_boundary_def_points,# - adjacent_subdomains = adjacent_subdomains,# - mesh_resolution = mesh_resolution,# - viscosity = viscosity,# - porosity = porosity,# - L = L,# - lambda_param = lambda_param,# - relative_permeability = relative_permeability,# - saturation = sat_pressure_relationship,# - starttime = starttime,# - number_of_timesteps = number_of_timesteps, - number_of_timesteps_to_analyse = number_of_timesteps_to_analyse, - timestep_size = timestep_size,# - sources = source_expression,# - initial_conditions = initial_condition,# - dirichletBC_expression_strings = dirichletBC,# - exact_solution = exact_solution,# - densities=densities, - include_gravity=True, - write2file = write_to_file,# - ) - -simulation.initialise() -# simulation.write_exact_solution_to_xdmf() -simulation.run() +for mesh_resolution in resolutions: + # initialise LDD simulation class + simulation = ldd.LDDsimulation( + tol=1E-14, + LDDsolver_tol=solver_tol, + debug=debugflag, + max_iter_num=max_iter_num, + FEM_Lagrange_degree=FEM_Lagrange_degree, + mesh_study=mesh_study + ) + + simulation.set_parameters(use_case=use_case, + output_dir=output_string, + subdomain_def_points=subdomain_def_points, + isRichards=isRichards, + interface_def_points=interface_def_points, + outer_boundary_def_points=outer_boundary_def_points, + adjacent_subdomains=adjacent_subdomains, + mesh_resolution=mesh_resolution, + viscosity=viscosity, + porosity=porosity, + L=L, + lambda_param=lambda_param, + relative_permeability=relative_permeability, + saturation=sat_pressure_relationship, + starttime=starttime, + number_of_timesteps=number_of_timesteps, + number_of_timesteps_to_analyse=number_of_timesteps_to_analyse, + plot_timestep_every=plot_timestep_every, + timestep_size=timestep_size, + sources=source_expression, + initial_conditions=initial_condition, + dirichletBC_expression_strings=dirichletBC, + exact_solution=exact_solution, + densities=densities, + include_gravity=include_gravity, + write2file=write_to_file, + ) + + simulation.initialise() + output_dir = simulation.output_dir + # simulation.write_exact_solution_to_xdmf() + output = simulation.run(analyse_condition=analyse_condition) + for subdomain_index, subdomain_output in output.items(): + mesh_h = subdomain_output['mesh_size'] + for phase, different_errornorms in subdomain_output['errornorm'].items(): + filename = output_dir + "subdomain{}-space-time-errornorm-{}-phase.csv".format(subdomain_index, phase) + # for errortype, errornorm in different_errornorms.items(): + + # eocfile = open("eoc_filename", "a") + # eocfile.write( str(mesh_h) + " " + str(errornorm) + "\n" ) + # eocfile.close() + # if subdomain.isRichards:mesh_h + data_dict = { + 'mesh_parameter': mesh_resolution, + 'mesh_h': mesh_h, + } + for error_type, errornorms in different_errornorms.items(): + data_dict.update( + {error_type: errornorms} + ) + errors = pd.DataFrame(data_dict, index=[mesh_resolution]) + # check if file exists + if os.path.isfile(filename) == True: + with open(filename, 'a') as f: + errors.to_csv(f, header=False, sep='\t', encoding='utf-8', index=False) + else: + errors.to_csv(filename, sep='\t', encoding='utf-8', index=False) diff --git a/TP-TP-2-patch-test-case/TP-TP-2-patch-test.py b/TP-TP-2-patch-test-case/TP-TP-2-patch-test.py index 3855efc..b878bc6 100755 --- a/TP-TP-2-patch-test-case/TP-TP-2-patch-test.py +++ b/TP-TP-2-patch-test-case/TP-TP-2-patch-test.py @@ -8,34 +8,67 @@ import domainPatch as dp import LDDsimulation as ldd import functools as ft import helpers as hlp +import datetime +import os +import pandas as pd + +date = datetime.datetime.now() +datestr = date.strftime("%Y-%m-%d") #import ufl as ufl # init sympy session sym.init_printing() -use_case = "TP-TP-two-patch" -solver_tol = 6E-6 - -############ GRID #######################ü -mesh_resolution = 20 -timestep_size = 0.0005 -number_of_timesteps = 600 +use_case = "TP-TP-2-patch" +solver_tol = 5E-7 +max_iter_num = 1000 +FEM_Lagrange_degree = 1 +mesh_study = False +resolutions = [20] + +############ GRID ####################### +# mesh_resolution = 20 +timestep_size = 0.0001 +number_of_timesteps = 5000 +plot_timestep_every = 10 # decide how many timesteps you want analysed. Analysed means, that we write out # subsequent errors of the L-iteration within the timestep. -number_of_timesteps_to_analyse = 0 -starttime = 0 +number_of_timesteps_to_analyse = 10 +starttime = 0.0 -Lw = 1 #/timestep_size +Lw = 0.25 #/timestep_size Lnw=Lw -lambda_w = 4 -lambda_nw = 4 +lambda_w = 40 +lambda_nw = 40 -include_gravity = True +include_gravity = False debugflag = False analyse_condition = True -output_string = "./output/2019-08-23-number_of_timesteps{}_".format(number_of_timesteps) +output_string = "./output/{}-{}_timesteps{}_P{}_solver_tol{}_".format(datestr, use_case, number_of_timesteps, FEM_Lagrange_degree, solver_tol) + +# toggle what should be written to files +if mesh_study: + write_to_file = { + 'space_errornorms': True, + 'meshes_and_markers': True, + 'L_iterations_per_timestep': False, + 'solutions': False, + 'absolute_differences': False, + 'condition_numbers': analyse_condition, + 'subsequent_errors': False + } +else: + write_to_file = { + 'space_errornorms': True, + 'meshes_and_markers': True, + 'L_iterations_per_timestep': False, + 'solutions': True, + 'absolute_differences': True, + 'condition_numbers': analyse_condition, + 'subsequent_errors': True + } ##### Domain and Interface #### # global simulation domain domain @@ -335,9 +368,9 @@ t = sym.symbols('t', positive=True) p_e_sym = { 1: {'wetting': (-6 - (1+t*t)*(1 + x*x + y*y)), #*cutoff, - 'nonwetting': (-1 -t*(1.1+ y + x**2))}, #*(sym.sin((1+y)/2*sym.pi)*sym.sin((1+x)/2*sym.pi))**2}, + 'nonwetting': (-1 -t*(1.1+ y*y))}, #*(sym.sin((1+y)/2*sym.pi)*sym.sin((1+x)/2*sym.pi))**2}, 2: {'wetting': (-6.0 - (1.0 + t*t)*(1.0 + x*x)), #*(sym.sin((1+y)/2*sym.pi)*sym.sin((1+x)/2*sym.pi))**2, - 'nonwetting': (-1 -t*(1.1 + x**2) - sym.sqrt(2+t**2)*(1.1+y)**2*y**2)}, #*(sym.sin((1+y)/2*sym.pi)*sym.sin((1+x)/2*sym.pi))**2}, + 'nonwetting': (-1 -t*(1.1 + y*y) - sym.sqrt(2+t**2)*(1.1+y)**2*y**2)}, #*(sym.sin((1+y)/2*sym.pi)*sym.sin((1+x)/2*sym.pi))**2}, } @@ -409,41 +442,71 @@ for subdomain in isRichards.keys(): # # sa -write_to_file = { - 'meshes_and_markers': True, - 'L_iterations': True -} - - -# initialise LDD simulation class -simulation = ldd.LDDsimulation(tol = 1E-14, LDDsolver_tol = solver_tol, debug = debugflag) -simulation.set_parameters(use_case=use_case, - output_dir = output_string,# - subdomain_def_points = subdomain_def_points,# - isRichards = isRichards,# - interface_def_points = interface_def_points,# - outer_boundary_def_points = outer_boundary_def_points,# - adjacent_subdomains = adjacent_subdomains,# - mesh_resolution = mesh_resolution,# - viscosity = viscosity,# - porosity = porosity,# - L = L,# - lambda_param = lambda_param,# - relative_permeability = relative_permeability,# - saturation = sat_pressure_relationship,# - starttime = starttime,# - number_of_timesteps = number_of_timesteps, - number_of_timesteps_to_analyse = number_of_timesteps_to_analyse, - timestep_size = timestep_size,# - sources = source_expression,# - initial_conditions = initial_condition,# - dirichletBC_expression_strings = dirichletBC,# - exact_solution = exact_solution,# - densities=densities, - include_gravity=include_gravity, - write2file = write_to_file,# - ) - -simulation.initialise() -# simulation.write_exact_solution_to_xdmf() -simulation.run(analyse_condition=analyse_condition) +for mesh_resolution in resolutions: + # initialise LDD simulation class + simulation = ldd.LDDsimulation( + tol=1E-14, + LDDsolver_tol=solver_tol, + debug=debugflag, + max_iter_num=max_iter_num, + FEM_Lagrange_degree=FEM_Lagrange_degree, + mesh_study=mesh_study + ) + + simulation.set_parameters(use_case=use_case, + output_dir=output_string, + subdomain_def_points=subdomain_def_points, + isRichards=isRichards, + interface_def_points=interface_def_points, + outer_boundary_def_points=outer_boundary_def_points, + adjacent_subdomains=adjacent_subdomains, + mesh_resolution=mesh_resolution, + viscosity=viscosity, + porosity=porosity, + L=L, + lambda_param=lambda_param, + relative_permeability=relative_permeability, + saturation=sat_pressure_relationship, + starttime=starttime, + number_of_timesteps=number_of_timesteps, + number_of_timesteps_to_analyse=number_of_timesteps_to_analyse, + plot_timestep_every=plot_timestep_every, + timestep_size=timestep_size, + sources=source_expression, + initial_conditions=initial_condition, + dirichletBC_expression_strings=dirichletBC, + exact_solution=exact_solution, + densities=densities, + include_gravity=include_gravity, + write2file=write_to_file, + ) + + simulation.initialise() + output_dir = simulation.output_dir + # simulation.write_exact_solution_to_xdmf() + output = simulation.run(analyse_condition=analyse_condition) + for subdomain_index, subdomain_output in output.items(): + mesh_h = subdomain_output['mesh_size'] + for phase, different_errornorms in subdomain_output['errornorm'].items(): + filename = output_dir + "subdomain{}-space-time-errornorm-{}-phase.csv".format(subdomain_index, phase) + # for errortype, errornorm in different_errornorms.items(): + + # eocfile = open("eoc_filename", "a") + # eocfile.write( str(mesh_h) + " " + str(errornorm) + "\n" ) + # eocfile.close() + # if subdomain.isRichards:mesh_h + data_dict = { + 'mesh_parameter': mesh_resolution, + 'mesh_h': mesh_h, + } + for error_type, errornorms in different_errornorms.items(): + data_dict.update( + {error_type: errornorms} + ) + errors = pd.DataFrame(data_dict, index=[mesh_resolution]) + # check if file exists + if os.path.isfile(filename) == True: + with open(filename, 'a') as f: + errors.to_csv(f, header=False, sep='\t', encoding='utf-8', index=False) + else: + errors.to_csv(filename, sep='\t', encoding='utf-8', index=False) -- GitLab